/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
#ifndef _MuRo_Devices_hpp_
#define _MuRo_Devices_hpp_

#include "Device.hpp"
#include "PositionClient.hpp"
#include "RangingClient.hpp"

#include "RangingDisplay.hpp"
#include "EnergyClient.hpp"
#include "SpeedCtrlClient.hpp"
#include "MapClient.hpp"
#include "AlarmClient.hpp"
#include "CoordinateDriveClient.hpp"
#include "MapDisplay.hpp"
#include "thread.hpp"
#include "DrivePath.hpp"
#include "AlarmBalloon.hpp"

namespace MuRo
{
  
  class CPositionDevice : public CDevice,
                          public MaCI::Position::CPositionClientCallback,
                          private gim::CSync
  {
    public:
      CPositionDevice(MaCI::Position::CPositionClient *positionClient, 
                      CMachine* machine);
      
      void Draw(const TViewParams &view);
      
      void DrawPickable(const TViewParams &view);
      
      void OnPositionDataEvent(const MaCI::Position::CPositionData& data, 
                     unsigned int seq, MaCI::Position::CPositionClient& client,
                     void * userPtr=NULL);
      
      void drawUnit(const TViewParams &view, bool selectionMode=false);
      void drawIcon(const TViewParams &view, bool selectionMode=false);
      void drawPointer(const TViewParams &view, bool selectionMode=false);
      void drawInfo(const TViewParams &view, int x, int y);
      void drawHistory(const TViewParams &view);
      
      bool IsPointVisible2D(const TViewParams &view, float x, float y);
      
      float positionX, positionY, heading;
      static const int infoBarHeight;
      static const int infoBarMinWidth;
      int infoBarWidth;
      bool showHistory;
      int historyLifetimeS;
      
    private:
      struct PoseWTime
      {
        PoseWTime(MaCI::Position::TPose2D pose, gim::time time)
          :pose(pose),time(time){}
        
        MaCI::Position::TPose2D pose;
        gim::time time;
      };
      std::list<PoseWTime> history;
  };

/******************************************************************************/
/******************************************************************************/
  
  class CRangingDevice : public CDevice
  {
    public:
      CRangingDevice(MaCI::Ranging::CRangingClient *rangingClient, 
                     CMachine* machine);
      
      void Draw(const TViewParams &view);
      
      //sets the position device that works as the reference position for ranging
      //if none is set, ranging is positioned to 0,0,0
      void SetPositionDevice(CPositionDevice *position);
      
      void GetDeviceInformation(int timeout);
      
      CRangingDisplay *rangingDisplay;
      
      //reference position for ranging
      CPositionDevice *positionDevice;
      
  };

/******************************************************************************/
/******************************************************************************/
  
  class CEnergyDevice : public CDevice,
                        public MaCI::Energy::CEnergyClientCallback
  {
    public:
      CEnergyDevice(MaCI::Energy::CEnergyClient *energyClient, 
                       CMachine* machine);
      
      void Draw(const TViewParams &view);
      
      void OnEnergyDataEvent(const MaCI::Energy::CEnergyData &aData, 
                             const unsigned int aDataSequence,
                             MaCI::Energy::CEnergyClient &aEnergyClient, void * userPtr=NULL);
      
      float energyLevel, maxEnergyLevel, energyConsumption;
  };
  
/******************************************************************************/
/******************************************************************************/
  
  class CSpeedCtrlDevice : public CDevice
  {
    public:
      CSpeedCtrlDevice(MaCI::SpeedCtrl::CSpeedCtrlClient *speedCtrlClient, 
                       CMachine* machine);
      
      void Draw(const TViewParams &view);
      
      MaCI::SpeedCtrl::TSpeed maxSpeed, minSpeed;
  };


/******************************************************************************/
/******************************************************************************/
  
  class CMapDevice : public CDevice , private gim::CThread
  {
    public:
      CMapDevice(MaCI::Map::CMapClient *mapClient, 
                 CMachine *machine);
      
      void Draw(const TViewParams &view);
      
      CMapDisplay *mapDisplay;
      
      int ThreadFunction(const int aThreadNumber);
      
      bool waiting;
  };
  

/******************************************************************************/
/******************************************************************************/
  
  class CCoordinateDriveDevice : public CDevice,
                   public MaCI::CoordinateDrive::CCoordinateDriveClientCallback
  {
  public:
    CCoordinateDriveDevice(MaCI::CoordinateDrive::CCoordinateDriveClient *coordinateDriveClient, 
                           CMachine* machine);
    
    void SetPickingContext(CGLPickingContext *context);
    
    void Draw(const TViewParams &view);
    
    void OnArrivedToPointEvent(const MaCI::CoordinateDrive::CCoordinateDriveData &aData, 
                               const unsigned int aDataSequence,
                               MaCI::CoordinateDrive::CCoordinateDriveClient 
                               &aCoordinateDriveClient, void * userPtr=NULL);
    
    void OnCoordinateEvent(const MaCI::CoordinateDrive::CCoordinateDriveData &aData, 
                           const unsigned int aDataSequence, 
                           MaCI::CoordinateDrive::CCoordinateDriveClient 
                           &aCoordinateDriveClient, void * userPtr=NULL);
    
    void OnServerStatusMessage(const MaCI::CoordinateDrive::CCoordinateDriveData &aData,
                               const unsigned int aDataSequence,
                               MaCI::CoordinateDrive::CCoordinateDriveClient &aCoordinateDriveClient,
                               void * aUserPtr = NULL);
    void AddPoint(float x, float y);
    
      void RemoveSelectedPoints();
      
      void StartDriving();
      
      void StopDriving();
      
    private:
      CDrivePath path;
      //CDrivePath editablePath, serverPath;
      CGLPickingContext *pickingContext;
  };
  


  
/******************************************************************************/
/******************************************************************************/
  
  class CAlarmDevice : public CDevice,
  public MaCI::Alarm::CAlarmClientCallback,
  private gim::CSync
  {
    public:
      CAlarmDevice(MaCI::Alarm::CAlarmClient *alarmClient, 
                  CMachine *machine);
        
      void OnAlarmDataEvent(const MaCI::Alarm::CAlarmData &aData, 
                            const unsigned int aDataSequence,
                            MaCI::Alarm::CAlarmClient &aAlarmClient);
      
      void Draw(const TViewParams &view);
      
      void SetPickingContext(CGLPickingContext *context);
      
      void RemoveAlarm(CAlarmBalloon *alarm);
      
      /*
      struct alarm
      {
        MaCI::Alarm::TAlarmEvent event;
        MaCI::Common::TTimestamp time;
      };*/
    
    private:
      std::list<CAlarmBalloon*> alarmArray;
      //std::list<alarm> alarmArray;
      CGLPickingContext *pickingContext;
  };

/******************************************************************************/
/******************************************************************************/

} //namespace MuRo

#endif
